﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using Rhizome.Contract;
using Rhizome.Internal;

namespace Rhizome.Model
{
	public class OnMessage : TriggerBase<object>, IMessageSink
	{
		/// <summary>
		/// XAML macro: Sets Criterion = new IfMessage&lt;TMessage&gt; {Message = value}
		/// </summary>
		public IMessage Message
		{
			get
			{
				var m = Criterion as IfMessage;
				return m == null ? null : m.Message;

			}
			set { Criterion = new IfMessage {Message = value}; }
		}

		/// <summary>
		/// XAML macro: Sets inner message criterion
		/// ((IfMessage&lt;TMessage&gt;)Criterion).Criterion = value 
		/// Plant for specific criterion will be replaced with current message
		/// </summary>
		public ICriterion MessageCriterion
		{
			get
			{
				var m = Criterion as IfMessage;
				return m == null ? null : m.Criterion;
			}
			set
			{
				var m = Criterion as IfMessage;
				if (m == null) throw new InvalidOperationException("Message Critetion must me set after Message");
				m.Criterion = value;
			}
		}

		/// <summary>
		/// If true instructs IMessageSink.Send to always return false (message was not handled)
		/// Default value is false
		/// </summary>
		public bool PathThrough { get; set; }

		#region Overrides of TriggerBase<object>

		public override void Initialize()
		{
		}

		public override void Cleanup()
		{
			var c = Criterion as IfMessage;
			if (c != null) c.CurrentMessage = null;
		}

		#endregion

		#region Implementation of IMessageSink

		bool IMessageSink.Send(object source, IMessage message, ICollection<IMessageSink> stack)
		{
			stack.Add(this);
			// todo: check thread
			var c = Criterion;
			var m = c as IfMessage;
			if (m != null) m.CurrentMessage = message;
			if (c == null || Send(() => c.Test()))
			{
				Post(() => Action.Process());
				
				return PathThrough == false;
			}

			return false;
		}

		#endregion

		#region Overrides of Object

		public override string ToString()
		{
			return "OnMessage {0}".With(Message);
		}

		#endregion
	}
}